<?php

namespace Wxwork\Http;

use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;


class Request
{

    private $logsDir;

    private $logsFile;

    private $proxy;

    private $proxyAccount;

    private $proxyPW;

    public function __construct($config)
    {
        $this->logsDir = $config['logsDir'] ?? '';
        $this->proxy = $config['proxy'] ?? '';

        $this->proxyAccount = $config['proxyAccount'] ?? '';
        $this->proxyPW = $config['proxyPW'] ?? '';
    }

    private function makeUrl(string $url, string $method, array $param): string
    {
        $url = API::$GATEWAY . $url;

        if ($method == 'GET') {
            $url .= '?' . http_build_query($param);
        }

        return $url;

    }

    private function makeOptions($method, $param): array
    {
        $option = [];
        $option['verify'] = false;
        $option['http_errors'] = false;

        $option['connect_timeout'] = 60;
        $option['timeout'] = 60;

        $option['debug'] = false;

        if ($this->proxy) {
            $option['proxy'] = $this->proxy;

            if ($this->proxyAccount and $this->proxyPW) {
                //代理 curl 设置账号密码
                $option['curl'] = [CURLOPT_PROXYUSERPWD => "{$this->proxyAccount}:{$this->proxyPW}"];
            }
        }

        if ($method == 'POST') {
            $option['json'] = $param;
        }

        if ($method =='FORM') {
            $option['multipart'] = $param;
        }

        return $option;
    }

    /**
     * 请求
     * @param string $url
     * @param string $method
     * @param array $param
     * @return Response
     */
    public function request(string $url, string $method, array $param): Response
    {
        self::mkLogsDir();

        $method = strtoupper($method);

        $response = new Response();

        $requestId = sha1(uniqid());

        self::requestLogs($requestId, $url, $method, $param);

        if ($GLOBALS['testResponse'] ?? '') {
            $string = $GLOBALS['testResponse'];
            $response->setBody($string);
            $response->setCode('200');
            $response->resolve();
            return $response;
        }

        try {
            $client = new Client();
            $option = self::makeOptions($method, $param);
            $url = self::makeUrl($url, $method, $param);

            if ($method == 'FORM') {
                $method = 'POST';
            }

            $result = $client->request($method, $url,$option);

            $body = $result->getBody()->getContents();

            self::responseLogs($requestId, $body);

            $status = $result->getStatusCode();

            if ($status != 200) {
                $response->setBody($body);
                throw new Exception($body);
            }

            $response->setCode($result->getStatusCode())
                ->setHeader($result->getHeaders())
                ->setBody($body)
                ->resolve();
            return $response;
        } catch (GuzzleException|Exception $exception) {
            self::responseLogs($requestId, $exception->getMessage());
            $response->setCode('500')
                ->setError($exception->getMessage());
            return $response;
        }

    }

    /**
     * 日记文件生成
     */
    private function mkLogsDir(): void
    {

        if (!$this->logsDir) {
            return;
        }

        $fileName = $this->logsDir . DIRECTORY_SEPARATOR . date('Ym');

        if (!is_dir($fileName)) {
            @mkdir($fileName, 0755, true);
        }

        $file = date('Ymd') . '.logs';

        $this->logsFile =  $fileName . '/' . $file;
    }

    /**
     * 请求日记
     * @param $uuid
     * @param $url
     * @param $method
     * @param $param
     * @return void
     */
    private function requestLogs($uuid, $url, $method, $param)
    {
        if (!$this->logsFile) {
            return;
        }
        $url = self::makeUrl($url, $method, $param);

        $urlLogs = date('Y-m-d H:i:s') . " URL      " . $uuid . " " . $url;

        file_put_contents($this->logsFile, $urlLogs . "\r\n", FILE_APPEND);

        if ($param) {
            if (is_array($param)) {
                $param = json_encode($param, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
            }
            $reqLogs = date('Y-m-d H:i:s') . " REQUEST  " . $uuid . " " . $param;
            file_put_contents($this->logsFile, $reqLogs . "\r\n", FILE_APPEND);
        }
    }

    /**
     * 返回日记
     * @param $uuid
     * @param $data
     * @return void
     */
    private function responseLogs($uuid, $data)
    {
        if (!$this->logsFile) {
            return;
        }

        $data = str_replace(["\r\n"], [''], $data);
        if (is_array($data)) {
            $data = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        }
        $repLogs = date('Y-m-d H:i:s') . " RESPONSE " . $uuid . " " . $data;

        file_put_contents($this->logsFile, $repLogs . "\r\n", FILE_APPEND);
    }
}
